diff --git a/src/main/java/me/mrletsplay/shareclientcore/connection/Change.java b/src/main/java/me/mrletsplay/shareclientcore/connection/Change.java index 7b65d83..0759e73 100644 --- a/src/main/java/me/mrletsplay/shareclientcore/connection/Change.java +++ b/src/main/java/me/mrletsplay/shareclientcore/connection/Change.java @@ -2,4 +2,4 @@ package me.mrletsplay.shareclientcore.connection; import me.mrletsplay.shareclientcore.document.Char; -public record Change(String documentPath, ChangeType type, Char character) {} +public record Change(ChangeType type, Char character) {} diff --git a/src/main/java/me/mrletsplay/shareclientcore/connection/message/ChangeMessage.java b/src/main/java/me/mrletsplay/shareclientcore/connection/message/ChangeMessage.java index 99b1155..47fb40c 100644 --- a/src/main/java/me/mrletsplay/shareclientcore/connection/message/ChangeMessage.java +++ b/src/main/java/me/mrletsplay/shareclientcore/connection/message/ChangeMessage.java @@ -3,12 +3,14 @@ package me.mrletsplay.shareclientcore.connection.message; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.Arrays; +import java.util.Objects; import me.mrletsplay.shareclientcore.connection.Change; import me.mrletsplay.shareclientcore.connection.ChangeType; import me.mrletsplay.shareclientcore.document.Char; -public record ChangeMessage(Change change) implements Message { +public record ChangeMessage(String documentPath, Change[] changes) implements Message { @Override public MessageType getType() { @@ -17,14 +19,43 @@ public record ChangeMessage(Change change) implements Message { @Override public void serialize(DataOutputStream out) throws IOException { - out.writeUTF(change.documentPath()); - out.writeUTF(change.type().name()); - change.character().serialize(out); + out.writeUTF(documentPath); + out.writeInt(changes.length); + for(int i = 0; i < changes.length; i++) { + out.writeUTF(changes[i].type().name()); + changes[i].character().serialize(out); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(changes); + result = prime * result + Objects.hash(documentPath); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ChangeMessage other = (ChangeMessage) obj; + return Arrays.equals(changes, other.changes) && Objects.equals(documentPath, other.documentPath); } public static ChangeMessage deserialize(DataInputStream in) throws IOException { try { - return new ChangeMessage(new Change(in.readUTF(), ChangeType.valueOf(in.readUTF()), Char.deserialize(in))); + String documentPath = in.readUTF(); + Change[] changes = new Change[in.readInt()]; + for(int i = 0; i < changes.length; i++) { + changes[i] = new Change(ChangeType.valueOf(in.readUTF()), Char.deserialize(in)); + } + return new ChangeMessage(documentPath, changes); }catch(IllegalArgumentException e) { throw new IOException("Invalid change type", e); } diff --git a/src/main/java/me/mrletsplay/shareclientcore/document/SharedDocument.java b/src/main/java/me/mrletsplay/shareclientcore/document/SharedDocument.java index f059630..3a60dd7 100644 --- a/src/main/java/me/mrletsplay/shareclientcore/document/SharedDocument.java +++ b/src/main/java/me/mrletsplay/shareclientcore/document/SharedDocument.java @@ -57,7 +57,7 @@ public class SharedDocument implements MessageListener { lamport++; Char ch = new Char(newPos, lamport, bytes[i]); if(charBag.add(ch) == -1) throw new IllegalStateException("Couldn't insert newly created char"); - changes[i] = new Change(path, ChangeType.ADD, ch); + changes[i] = new Change(ChangeType.ADD, ch); charBefore = ch; } @@ -87,12 +87,10 @@ public class SharedDocument implements MessageListener { public void localInsert(int index, String str) { Change[] changes = insert(index, str, site); - for(Change c : changes) { - try { - connection.send(new ChangeMessage(c)); - } catch (ConnectionException e) { - e.printStackTrace(); // TODO: throw error - } + try { + connection.send(new ChangeMessage(path, changes)); + } catch (ConnectionException e) { + e.printStackTrace(); // TODO: throw error } } @@ -109,16 +107,14 @@ public class SharedDocument implements MessageListener { while(n-- > 0) { // TODO: more efficient implementation (e.g. range delete in CharBag) Char toRemove = charBag.get(index + 1); - changes[n] = new Change(path, ChangeType.REMOVE, toRemove); + changes[n] = new Change(ChangeType.REMOVE, toRemove); if(charBag.remove(toRemove) == -1) throw new IllegalStateException("Couldn't remove existing char"); } - for(Change c : changes) { - try { - connection.send(new ChangeMessage(c)); - } catch (ConnectionException e) { - e.printStackTrace(); // TODO: throw error - } + try { + connection.send(new ChangeMessage(path, changes)); + } catch (ConnectionException e) { + e.printStackTrace(); // TODO: throw error } } @@ -191,12 +187,13 @@ public class SharedDocument implements MessageListener { @Override public void onMessage(Message message) { if(message instanceof ChangeMessage change) { - Change c = change.change(); - if(!c.documentPath().equals(path)) return; + if(!change.documentPath().equals(path)) return; - switch(c.type()) { - case ADD -> remoteInsert(c.character()); - case REMOVE -> remoteDelete(c.character()); + for(Change c : change.changes()) { + switch(c.type()) { + case ADD -> remoteInsert(c.character()); + case REMOVE -> remoteDelete(c.character()); + } } } } diff --git a/src/test/java/me/mrletsplay/shareclientcore/CharBagTest.java b/src/test/java/me/mrletsplay/shareclientcore/CharBagTest.java index 75f4662..1a95115 100644 --- a/src/test/java/me/mrletsplay/shareclientcore/CharBagTest.java +++ b/src/test/java/me/mrletsplay/shareclientcore/CharBagTest.java @@ -9,7 +9,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import me.mrletsplay.shareclientcore.document.ArrayCharBag; -import me.mrletsplay.shareclientcore.document.BinaryTreeCharBag; import me.mrletsplay.shareclientcore.document.Char; import me.mrletsplay.shareclientcore.document.CharBag; import me.mrletsplay.shareclientcore.document.Identifier; @@ -17,7 +16,7 @@ import me.mrletsplay.shareclientcore.document.Identifier; public class CharBagTest { private static List getBags() { - return List.of(new ArrayCharBag(), new BinaryTreeCharBag()); + return List.of(new ArrayCharBag()/*, new BinaryTreeCharBag() TODO implement BinaryTreeCharBag */); } @ParameterizedTest diff --git a/src/test/java/me/mrletsplay/shareclientcore/MessageTest.java b/src/test/java/me/mrletsplay/shareclientcore/MessageTest.java index 5a98855..123d228 100644 --- a/src/test/java/me/mrletsplay/shareclientcore/MessageTest.java +++ b/src/test/java/me/mrletsplay/shareclientcore/MessageTest.java @@ -42,8 +42,12 @@ public class MessageTest { @Test public void testChangeMessage() throws IOException { - Change change = new Change("Project:src/test.txt", ChangeType.ADD, new Char(new Identifier[] {new Identifier(0, 1), new Identifier(1, 3)}, 42, (byte) 'e')); - ChangeMessage m = new ChangeMessage(change); + Change[] changes = { + new Change(ChangeType.ADD, new Char(new Identifier[] {new Identifier(0, 1), new Identifier(1, 3)}, 42, (byte) 'e')), + new Change(ChangeType.REMOVE, new Char(new Identifier[] {new Identifier(2, 1), new Identifier(1, 4)}, 314, (byte) 'q')), + + }; + ChangeMessage m = new ChangeMessage("Project:src/test.txt", changes); assertEquals(deserialize(serialize(m)), m, "Deserialized message must equal message"); }