Allow multiple changes per ChangeMessage

This commit is contained in:
MrLetsplay 2024-06-22 18:51:29 +02:00
parent a64a685e75
commit 872e2842b9
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
5 changed files with 60 additions and 29 deletions

View File

@ -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) {}

View File

@ -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);
}

View File

@ -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());
}
}
}
}

View File

@ -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<CharBag> getBags() {
return List.of(new ArrayCharBag(), new BinaryTreeCharBag());
return List.of(new ArrayCharBag()/*, new BinaryTreeCharBag() TODO implement BinaryTreeCharBag */);
}
@ParameterizedTest

View File

@ -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");
}