This commit is contained in:
Frank 2021-08-06 23:20:39 +02:00
parent 6883287c72
commit 3438c86de2
6 changed files with 182 additions and 169 deletions

View file

@ -23,7 +23,7 @@ import java.util.function.Predicate;
* You can compare instances using {@link #equals(Object)} to determine if two files are * You can compare instances using {@link #equals(Object)} to determine if two files are
* identical. * identical.
*/ */
public class FileHash { public class FileHash extends DataExchange.AutoSyncID {
/** /**
* The md5-hash of the file * The md5-hash of the file
*/ */
@ -40,35 +40,19 @@ public class FileHash {
*/ */
public final int value; public final int value;
/**
* A Unique ID for the referenced File.
* <p>
* Files with the same {@link #modID} need to have a unique IDs. Normally the filename from {@link #FileHash(String, File, byte[], int, int)}
* is used to generated that ID, but you can directly specify one using {@link #FileHash(String, String, byte[], int, int)}.
*/
@NotNull
public final String uniqueID;
/**
* The ID of the Mod that is registering the File
*/
@NotNull
public final String modID;
FileHash(String modID, File file, byte[] md5, int size, int value) { FileHash(String modID, File file, byte[] md5, int size, int value) {
this(modID, file.getName(), md5, size, value); this(modID, file.getName(), md5, size, value);
} }
FileHash(String modID, String uniqueID, byte[] md5, int size, int value) { FileHash(String modID, String uniqueID, byte[] md5, int size, int value) {
Objects.nonNull(modID); super(modID, uniqueID);
Objects.nonNull(uniqueID);
Objects.nonNull(md5); Objects.nonNull(md5);
this.md5 = md5; this.md5 = md5;
this.size = size; this.size = size;
this.value = value; this.value = value;
this.modID = modID;
this.uniqueID = uniqueID;
} }
private static int ERR_DOES_NOT_EXIST = -10; private static int ERR_DOES_NOT_EXIST = -10;
@ -85,7 +69,7 @@ public class FileHash {
@Override @Override
public String toString() { public String toString() {
return String.format("%08x", size) return super.toString()+": "+String.format("%08x", size)
+ "-" + "-"
+ String.format("%08x", value) + String.format("%08x", value)
+ "-" + "-"

View file

@ -0,0 +1,123 @@
package ru.bclib.api.dataexchange.handler;
import net.minecraft.network.FriendlyByteBuf;
import ru.bclib.api.dataexchange.DataHandler;
import ru.bclib.api.dataexchange.FileHash;
import ru.bclib.util.Pair;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
class AutoFileSyncEntry extends DataExchange.AutoSyncID {
public final DataExchange.NeedTransferPredicate needTransfer;
public final File fileName;
public final boolean requestContent;
private FileHash hash;
AutoFileSyncEntry(String modID, File fileName, boolean requestContent, DataExchange.NeedTransferPredicate needTransfer) {
this(modID, fileName.getName(), fileName, requestContent, needTransfer);
}
AutoFileSyncEntry(String modID, String uniqueID, File fileName, boolean requestContent, DataExchange.NeedTransferPredicate needTransfer) {
super(modID, uniqueID);
this.needTransfer = needTransfer;
this.fileName = fileName;
this.requestContent = requestContent;
}
public FileHash getFileHash() {
if (hash == null)
{
hash = FileHash.create(modID, fileName, uniqueID);
}
return hash;
}
public byte[] getContent() {
if (!fileName.exists()) return new byte[0];
final Path path = fileName.toPath();
try {
return Files.readAllBytes(path);
} catch (IOException e) {
}
return new byte[0];
}
public int serializeContent(FriendlyByteBuf buf) {
DataHandler.writeString(buf, modID);
DataHandler.writeString(buf, uniqueID);
return serializeFileContent(buf);
}
public static Pair<AutoFileSyncEntry, byte[]> deserializeContent(FriendlyByteBuf buf) {
final String modID = DataHandler.readString(buf);
final String uniqueID = DataHandler.readString(buf);
byte[] data = deserializeFileContent(buf);
AutoFileSyncEntry entry = AutoFileSyncEntry.findMatching(modID, uniqueID);
return new Pair<>(entry, data);
}
public void serialize(FriendlyByteBuf buf) {
getFileHash().serialize(buf);
buf.writeBoolean(requestContent);
if (requestContent) {
serializeFileContent(buf);
}
}
public static DataExchange.AutoSyncTriple deserializeAndMatch(FriendlyByteBuf buf) {
Pair<FileHash, byte[]> e = deserialize(buf);
AutoFileSyncEntry match = findMatching(e.first);
return new DataExchange.AutoSyncTriple(e.first, e.second, match);
}
public static Pair<FileHash, byte[]> deserialize(FriendlyByteBuf buf) {
FileHash hash = FileHash.deserialize(buf);
boolean withContent = buf.readBoolean();
byte[] data = null;
if (withContent) {
data = deserializeFileContent(buf);
}
return new Pair(hash, data);
}
private int serializeFileContent(FriendlyByteBuf buf) {
byte[] content = getContent();
buf.writeInt(content.length);
buf.writeByteArray(content);
return content.length;
}
private static byte[] deserializeFileContent(FriendlyByteBuf buf) {
byte[] data;
int size = buf.readInt();
data = buf.readByteArray(size);
return data;
}
public static AutoFileSyncEntry findMatching(FileHash hash) {
return findMatching(hash.modID, hash.uniqueID);
}
public static AutoFileSyncEntry findMatching(DataExchange.AutoSyncID aid) {
return findMatching(aid.modID, aid.uniqueID);
}
public static AutoFileSyncEntry findMatching(String modID, String uniqueID) {
return DataExchange
.getInstance()
.autoSyncFiles
.stream()
.filter(asf -> asf.modID.equals(modID) && asf.uniqueID.equals(uniqueID))
.findFirst()
.orElse(null);
}
}

View file

@ -5,7 +5,7 @@ import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.minecraft.network.FriendlyByteBuf; import org.jetbrains.annotations.NotNull;
import ru.bclib.api.dataexchange.ConnectorClientside; import ru.bclib.api.dataexchange.ConnectorClientside;
import ru.bclib.api.dataexchange.ConnectorServerside; import ru.bclib.api.dataexchange.ConnectorServerside;
import ru.bclib.api.dataexchange.DataExchangeAPI; import ru.bclib.api.dataexchange.DataExchangeAPI;
@ -16,17 +16,11 @@ import ru.bclib.util.Pair;
import ru.bclib.util.Triple; import ru.bclib.util.Triple;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
abstract public class DataExchange { abstract public class DataExchange {
@FunctionalInterface @FunctionalInterface
@ -34,21 +28,50 @@ abstract public class DataExchange {
public boolean test(FileHash clientHash, FileHash serverHash, byte[] content); public boolean test(FileHash clientHash, FileHash serverHash, byte[] content);
} }
final static class AutoSyncID extends Pair<String, String>{ public static class AutoSyncID {
/**
* A Unique ID for the referenced File.
* <p>
* Files with the same {@link #modID} need to have a unique IDs. Normally the filename from {@link #FileHash(String, File, byte[], int, int)}
* is used to generated that ID, but you can directly specify one using {@link #FileHash(String, String, byte[], int, int)}.
*/
@NotNull
public final String uniqueID;
/**
* The ID of the Mod that is registering the File
*/
@NotNull
public final String modID;
public AutoSyncID(String modID, String uniqueID) { public AutoSyncID(String modID, String uniqueID) {
super(modID, uniqueID); Objects.nonNull(modID);
Objects.nonNull(uniqueID);
this.modID = modID;
this.uniqueID = uniqueID;
} }
public String getModID() { return this.first; }
public String getUniqueID() { return this.second; }
@Override @Override
public String toString() { public String toString() {
return first+"."+second; return modID+"."+uniqueID;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AutoSyncID that = (AutoSyncID) o;
return uniqueID.equals(that.uniqueID) && modID.equals(that.modID);
}
@Override
public int hashCode() {
return Objects.hash(uniqueID, modID);
} }
} }
final static class AutoSyncTriple extends Triple<FileHash, byte[], DataExchange.AutoFileSyncEntry>{ final static class AutoSyncTriple extends Triple<FileHash, byte[], AutoFileSyncEntry>{
public AutoSyncTriple(FileHash first, byte[] second, AutoFileSyncEntry third) { public AutoSyncTriple(FileHash first, byte[] second, AutoFileSyncEntry third) {
super(first, second, third); super(first, second, third);
} }
@ -58,117 +81,6 @@ abstract public class DataExchange {
return first.modID+"."+first.uniqueID; return first.modID+"."+first.uniqueID;
} }
} }
static class AutoFileSyncEntry {
public final NeedTransferPredicate needTransfer;
public final File fileName;
public final String modID;
public final String uniqueID;
public final boolean requestContent;
private FileHash hash;
AutoFileSyncEntry(String modID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer) {
this(modID, fileName.getName(), fileName, requestContent, needTransfer);
}
AutoFileSyncEntry(String modID, String uniqueID, File fileName, boolean requestContent, NeedTransferPredicate needTransfer) {
this.needTransfer = needTransfer;
this.fileName = fileName;
this.modID = modID;
this.uniqueID = uniqueID;
this.requestContent = requestContent;
}
public FileHash getFileHash(){
if (hash == null) {
hash = FileHash.create(modID, fileName, uniqueID);
}
return hash;
}
public byte[] getContent(){
if (!fileName.exists()) return new byte[0];
final Path path = fileName.toPath();
try {
return Files.readAllBytes(path);
} catch (IOException e) {
}
return new byte[0];
}
public int serializeContent(FriendlyByteBuf buf){
DataHandler.writeString(buf, modID);
DataHandler.writeString(buf, uniqueID);
return serializeFileContent(buf);
}
public static Pair<AutoFileSyncEntry, byte[]> deserializeContent(FriendlyByteBuf buf){
final String modID = DataHandler.readString(buf);
final String uniqueID = DataHandler.readString(buf);
byte[] data = deserializeFileContent(buf);
AutoFileSyncEntry entry = AutoFileSyncEntry.findMatching(modID, uniqueID);
return new Pair<>(entry, data);
}
public void serialize(FriendlyByteBuf buf){
getFileHash().serialize(buf);
buf.writeBoolean(requestContent);
if (requestContent) {
serializeFileContent(buf);
}
}
public static AutoSyncTriple deserializeAndMatch(FriendlyByteBuf buf){
Pair<FileHash, byte[]> e = deserialize(buf);
AutoFileSyncEntry match = findMatching(e.first);
return new AutoSyncTriple(e.first, e.second, match);
}
public static Pair<FileHash, byte[]> deserialize(FriendlyByteBuf buf){
FileHash hash = FileHash.deserialize(buf);
boolean withContent = buf.readBoolean();
byte[] data = null;
if (withContent) {
data = deserializeFileContent(buf);
}
return new Pair(hash, data);
}
private int serializeFileContent(FriendlyByteBuf buf) {
byte[] content = getContent();
buf.writeInt(content.length);
buf.writeByteArray(content);
return content.length;
}
private static byte[] deserializeFileContent(FriendlyByteBuf buf) {
byte[] data;
int size = buf.readInt();
data = buf.readByteArray(size);
return data;
}
public static AutoFileSyncEntry findMatching(FileHash hash){
return findMatching(hash.modID, hash.uniqueID);
}
public static AutoFileSyncEntry findMatching(AutoSyncID aid){
return findMatching(aid.getModID(), aid.getUniqueID());
}
public static AutoFileSyncEntry findMatching(String modID, String uniqueID){
return DataExchange
.getInstance()
.autoSyncFiles
.stream()
.filter(asf -> asf.modID.equals(modID) && asf.uniqueID.equals(uniqueID))
.findFirst()
.orElse(null);
}
}
private static DataExchangeAPI instance; private static DataExchangeAPI instance;
protected static DataExchangeAPI getInstance(){ protected static DataExchangeAPI getInstance(){

View file

@ -67,10 +67,10 @@ public class HelloClient extends DataHandler {
} }
//send config Data //send config Data
final List<DataExchange.AutoFileSyncEntry> autoSyncFiles = DataExchange.getInstance().autoSyncFiles; final List<AutoFileSyncEntry> autoSyncFiles = DataExchange.getInstance().autoSyncFiles;
buf.writeInt(autoSyncFiles.size()); buf.writeInt(autoSyncFiles.size());
for (DataExchange.AutoFileSyncEntry entry : autoSyncFiles) { for (AutoFileSyncEntry entry : autoSyncFiles) {
System.out.println("Serializing " + entry.getFileHash()); //System.out.println("Serializing " + entry.getFileHash());
entry.serialize(buf); entry.serialize(buf);
} }
} }
@ -96,10 +96,10 @@ public class HelloClient extends DataHandler {
count = buf.readInt(); count = buf.readInt();
autoSyncedFiles = new ArrayList<>(count); autoSyncedFiles = new ArrayList<>(count);
for (int i=0; i< count; i++) { for (int i=0; i< count; i++) {
System.out.println("Deserializing "); //System.out.println("Deserializing ");
DataExchange.AutoSyncTriple t = DataExchange.AutoFileSyncEntry.deserializeAndMatch(buf); DataExchange.AutoSyncTriple t = AutoFileSyncEntry.deserializeAndMatch(buf);
autoSyncedFiles.add(t); autoSyncedFiles.add(t);
System.out.println(t.first); //System.out.println(t.first);
} }
} }

View file

@ -37,8 +37,8 @@ public class RequestFiles extends DataHandler {
buf.writeInt(files.size()); buf.writeInt(files.size());
for (AutoSyncID a : files){ for (AutoSyncID a : files){
writeString(buf, a.getModID()); writeString(buf, a.modID);
writeString(buf, a.getUniqueID()); writeString(buf, a.uniqueID);
} }
} }
@ -63,16 +63,14 @@ public class RequestFiles extends DataHandler {
@Override @Override
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) { protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
List<DataExchange.AutoFileSyncEntry> syncEntries = files List<AutoFileSyncEntry> syncEntries = files
.stream().map(asid -> DataExchange.AutoFileSyncEntry.findMatching(asid)) .stream().map(asid -> AutoFileSyncEntry.findMatching(asid))
.filter(e -> e!=null) .filter(e -> e!=null)
.collect(Collectors.toList()); .collect(Collectors.toList());
reply(new SendFiles(syncEntries, receivedToken), server); reply(new SendFiles(syncEntries, receivedToken), server);
} }
public static void newToken(){ public static void newToken(){
currentToken = UUID.randomUUID().toString(); currentToken = UUID.randomUUID().toString();
} }

View file

@ -12,28 +12,24 @@ import ru.bclib.BCLib;
import ru.bclib.api.dataexchange.DataHandler; import ru.bclib.api.dataexchange.DataHandler;
import ru.bclib.api.dataexchange.DataHandlerDescriptor; import ru.bclib.api.dataexchange.DataHandlerDescriptor;
import ru.bclib.gui.screens.ConfirmRestartScreen; import ru.bclib.gui.screens.ConfirmRestartScreen;
import ru.bclib.gui.screens.SyncFilesScreen;
import ru.bclib.util.Pair; import ru.bclib.util.Pair;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class SendFiles extends DataHandler { public class SendFiles extends DataHandler {
public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "send_files"), SendFiles::new, false, false); public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "send_files"), SendFiles::new, false, false);
protected List<DataExchange.AutoFileSyncEntry> files; protected List<AutoFileSyncEntry> files;
private String token = ""; private String token = "";
public SendFiles(){ public SendFiles(){
this(null, ""); this(null, "");
} }
public SendFiles(List<DataExchange.AutoFileSyncEntry> files, String token) { public SendFiles(List<AutoFileSyncEntry> files, String token) {
super(DESCRIPTOR.IDENTIFIER, true); super(DESCRIPTOR.IDENTIFIER, true);
this.files = files; this.files = files;
this.token = token; this.token = token;
@ -41,18 +37,18 @@ public class SendFiles extends DataHandler {
@Override @Override
protected void serializeData(FriendlyByteBuf buf) { protected void serializeData(FriendlyByteBuf buf) {
List<DataExchange.AutoFileSyncEntry> existingFiles = files.stream().filter(e -> e.fileName.exists()).collect(Collectors.toList()); List<AutoFileSyncEntry> existingFiles = files.stream().filter(e -> e.fileName.exists()).collect(Collectors.toList());
writeString(buf, token); writeString(buf, token);
buf.writeInt(existingFiles.size()); buf.writeInt(existingFiles.size());
BCLib.LOGGER.info("Sending " + existingFiles.size() + " Files to Client:"); BCLib.LOGGER.info("Sending " + existingFiles.size() + " Files to Client:");
for (DataExchange.AutoFileSyncEntry entry : existingFiles) { for (AutoFileSyncEntry entry : existingFiles) {
int length = entry.serializeContent(buf); int length = entry.serializeContent(buf);
BCLib.LOGGER.info(" - " + entry + " (" + length + " Bytes)"); BCLib.LOGGER.info(" - " + entry + " (" + length + " Bytes)");
} }
} }
private List<Pair<DataExchange.AutoFileSyncEntry, byte[]>> receivedFiles; private List<Pair<AutoFileSyncEntry, byte[]>> receivedFiles;
@Override @Override
protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) { protected void deserializeFromIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean fromClient) {
token = readString(buf); token = readString(buf);
@ -66,7 +62,7 @@ public class SendFiles extends DataHandler {
receivedFiles = new ArrayList<>(size); receivedFiles = new ArrayList<>(size);
BCLib.LOGGER.info("Server sent " + size + " Files:"); BCLib.LOGGER.info("Server sent " + size + " Files:");
for (int i=0; i<size; i++){ for (int i=0; i<size; i++){
Pair<DataExchange.AutoFileSyncEntry, byte[]> p = DataExchange.AutoFileSyncEntry.deserializeContent(buf); Pair<AutoFileSyncEntry, byte[]> p = AutoFileSyncEntry.deserializeContent(buf);
if (p.first != null) { if (p.first != null) {
receivedFiles.add(p); receivedFiles.add(p);
BCLib.LOGGER.info(" - " + p.first + " (" + p.second.length + " Bytes)"); BCLib.LOGGER.info(" - " + p.first + " (" + p.second.length + " Bytes)");
@ -79,8 +75,8 @@ public class SendFiles extends DataHandler {
@Override @Override
protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) { protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient) {
BCLib.LOGGER.info("Writing Files:"); BCLib.LOGGER.info("Writing Files:");
for (Pair<DataExchange.AutoFileSyncEntry, byte[]> entry : receivedFiles) { for (Pair<AutoFileSyncEntry, byte[]> entry : receivedFiles) {
final DataExchange.AutoFileSyncEntry e = entry.first; final AutoFileSyncEntry e = entry.first;
final byte[] data = entry.second; final byte[] data = entry.second;
Path path = e.fileName.toPath(); Path path = e.fileName.toPath();
BCLib.LOGGER.info(" - Writing " + path + " (" + data.length + " Bytes)"); BCLib.LOGGER.info(" - Writing " + path + " (" + data.length + " Bytes)");