Add more protocol stuff
This commit is contained in:
parent
72b4e547fb
commit
e802d50863
@ -2,4 +2,4 @@ package me.mrletsplay.shareclientcore.connection;
|
||||
|
||||
import me.mrletsplay.shareclientcore.document.Char;
|
||||
|
||||
public record Change(int document, ChangeType type, Char character) {}
|
||||
public record Change(String documentPath, ChangeType type, Char character) {}
|
||||
|
@ -9,6 +9,11 @@ public class DummyConnection implements RemoteConnection {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSiteID() {
|
||||
return 0;
|
||||
|
@ -11,6 +11,8 @@ public interface RemoteConnection {
|
||||
|
||||
public void connect(String sessionID) throws ConnectionException;
|
||||
|
||||
public void disconnect();
|
||||
|
||||
public int getSiteID();
|
||||
|
||||
public void send(Message message) throws ConnectionException;
|
||||
|
@ -11,6 +11,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.framing.CloseFrame;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
|
||||
import me.mrletsplay.shareclientcore.connection.message.ClientHelloMessage;
|
||||
@ -43,14 +44,22 @@ public class WebSocketConnection implements RemoteConnection {
|
||||
try {
|
||||
if(!client.connectBlocking(30, TimeUnit.SECONDS)) throw new IOException("Failed to connect to WebSocket server");
|
||||
send(new ClientHelloMessage(username, sessionID));
|
||||
wait.wait(30_000L);
|
||||
if(!helloReceived) throw new ConnectionException("Server did not send hello");
|
||||
synchronized(wait) { wait.wait(30_000L); }
|
||||
if(!helloReceived) {
|
||||
client.close();
|
||||
throw new ConnectionException("Server did not send hello");
|
||||
}
|
||||
if(connectException != null) throw connectException;
|
||||
} catch (InterruptedException | IOException e) {
|
||||
throw new ConnectionException("Failed to establish connection", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
client.close(CloseFrame.NORMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSiteID() {
|
||||
return siteID;
|
||||
@ -120,7 +129,7 @@ public class WebSocketConnection implements RemoteConnection {
|
||||
close();
|
||||
}
|
||||
|
||||
wait.notifyAll();
|
||||
synchronized(wait) { wait.notifyAll(); }
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
package me.mrletsplay.shareclientcore.connection.message;
|
||||
|
||||
public interface AddressableMessage extends Message {
|
||||
|
||||
public int siteID();
|
||||
|
||||
}
|
@ -17,14 +17,14 @@ public record ChangeMessage(Change change) implements Message {
|
||||
|
||||
@Override
|
||||
public void serialize(DataOutputStream out) throws IOException {
|
||||
out.writeInt(change.document());
|
||||
out.writeUTF(change.documentPath());
|
||||
out.writeUTF(change.type().name());
|
||||
change.character().serialize(out);
|
||||
}
|
||||
|
||||
public static ChangeMessage deserialize(DataInputStream in) throws IOException {
|
||||
try {
|
||||
return new ChangeMessage(new Change(in.readInt(), ChangeType.valueOf(in.readUTF()), Char.deserialize(in)));
|
||||
return new ChangeMessage(new Change(in.readUTF(), ChangeType.valueOf(in.readUTF()), Char.deserialize(in)));
|
||||
}catch(IllegalArgumentException e) {
|
||||
throw new IOException("Invalid change type", e);
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package me.mrletsplay.shareclientcore.connection.message;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public record ChecksumMessage(int siteID, String documentPath, byte[] checksum) implements AddressableMessage {
|
||||
|
||||
@Override
|
||||
public MessageType getType() {
|
||||
return MessageType.CHECKSUM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(DataOutputStream out) throws IOException {
|
||||
out.writeInt(siteID);
|
||||
out.writeUTF(documentPath);
|
||||
out.writeInt(checksum.length);
|
||||
out.write(checksum);
|
||||
}
|
||||
|
||||
public static ChecksumMessage deserialize(DataInputStream in) throws IOException {
|
||||
try {
|
||||
return new ChecksumMessage(in.readInt(), in.readUTF(), in.readNBytes(in.readInt()));
|
||||
}catch(IllegalArgumentException e) {
|
||||
throw new IOException("Invalid checksum length", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package me.mrletsplay.shareclientcore.connection.message;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public record FullSyncMessage(int siteID, String documentPath, byte[] content) implements AddressableMessage {
|
||||
|
||||
@Override
|
||||
public MessageType getType() {
|
||||
return MessageType.FULL_SYNC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(DataOutputStream out) throws IOException {
|
||||
out.writeInt(siteID);
|
||||
out.writeUTF(documentPath);
|
||||
out.writeInt(content.length);
|
||||
out.write(content);
|
||||
}
|
||||
|
||||
public static FullSyncMessage deserialize(DataInputStream in) throws IOException {
|
||||
try {
|
||||
return new FullSyncMessage(in.readInt(), in.readUTF(), in.readNBytes(in.readInt()));
|
||||
}catch(IllegalArgumentException e) {
|
||||
throw new IOException("Invalid content length", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package me.mrletsplay.shareclientcore.connection.message;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public record RequestChecksumMessage(int siteID, String documentPath) implements AddressableMessage {
|
||||
|
||||
@Override
|
||||
public MessageType getType() {
|
||||
return MessageType.REQUEST_CHECKSUM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(DataOutputStream out) throws IOException {
|
||||
out.writeInt(siteID);
|
||||
out.writeUTF(documentPath);
|
||||
}
|
||||
|
||||
public static RequestChecksumMessage deserialize(DataInputStream in) throws IOException {
|
||||
return new RequestChecksumMessage(in.readInt(), in.readUTF());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package me.mrletsplay.shareclientcore.connection.message;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public record RequestFullSyncMessage(int siteID, String documentPath) implements AddressableMessage {
|
||||
|
||||
@Override
|
||||
public MessageType getType() {
|
||||
return MessageType.REQUEST_FULL_SYNC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(DataOutputStream out) throws IOException {
|
||||
out.writeInt(siteID);
|
||||
out.writeBoolean(documentPath != null);
|
||||
if(documentPath != null) out.writeUTF(documentPath);
|
||||
}
|
||||
|
||||
public static RequestFullSyncMessage deserialize(DataInputStream in) throws IOException {
|
||||
return new RequestFullSyncMessage(in.readInt(), in.readBoolean() ? in.readUTF() : null);
|
||||
}
|
||||
|
||||
}
|
@ -16,12 +16,12 @@ public class SharedDocument implements MessageListener {
|
||||
|
||||
private RemoteConnection connection;
|
||||
private CharBag charBag;
|
||||
private int document;
|
||||
private String path;
|
||||
private int site;
|
||||
private int lamport;
|
||||
private Set<DocumentListener> listeners;
|
||||
|
||||
public SharedDocument(RemoteConnection connection) {
|
||||
public SharedDocument(RemoteConnection connection, String path) {
|
||||
this.connection = connection;
|
||||
connection.addListener(this);
|
||||
|
||||
@ -29,7 +29,7 @@ public class SharedDocument implements MessageListener {
|
||||
charBag.add(Char.START_OF_DOCUMENT);
|
||||
charBag.add(Char.END_OF_DOCUMENT);
|
||||
|
||||
this.document = 0; // TODO: implement
|
||||
this.path = path;
|
||||
this.site = connection.getSiteID();
|
||||
this.listeners = new HashSet<>();
|
||||
}
|
||||
@ -52,7 +52,7 @@ public class SharedDocument implements MessageListener {
|
||||
lamport++;
|
||||
Char ch = new Char(newPos, lamport, chars[i]);
|
||||
charBag.add(ch);
|
||||
changes[i] = new Change(document, ChangeType.ADD, ch);
|
||||
changes[i] = new Change(path, ChangeType.ADD, ch);
|
||||
charBefore = ch;
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ 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(document, ChangeType.REMOVE, toRemove);
|
||||
changes[n] = new Change(path, ChangeType.REMOVE, toRemove);
|
||||
charBag.remove(toRemove);
|
||||
}
|
||||
|
||||
@ -139,6 +139,8 @@ public class SharedDocument implements MessageListener {
|
||||
public void onMessage(Message message) {
|
||||
if(message instanceof ChangeMessage change) {
|
||||
Change c = change.change();
|
||||
if(!c.documentPath().equals(path)) return;
|
||||
|
||||
System.out.println("Change: " + c + " | " + Arrays.toString(c.character().position()));
|
||||
switch(c.type()) {
|
||||
case ADD -> remoteInsert(c.character());
|
||||
|
@ -12,7 +12,7 @@ public class DocumentTest {
|
||||
|
||||
@Test
|
||||
public void testLocalInsert() {
|
||||
SharedDocument doc = new SharedDocument(new DummyConnection());
|
||||
SharedDocument doc = new SharedDocument(new DummyConnection(), "test");
|
||||
doc.localInsert(0, "Hello");
|
||||
assertEquals("Hello", doc.getContents());
|
||||
doc.localInsert(5, " World");
|
||||
@ -23,7 +23,7 @@ public class DocumentTest {
|
||||
|
||||
@Test
|
||||
public void testLocalInsertInvalidIndexFails() {
|
||||
SharedDocument doc = new SharedDocument(new DummyConnection());
|
||||
SharedDocument doc = new SharedDocument(new DummyConnection(), "test");
|
||||
doc.localInsert(0, "Hello");
|
||||
assertThrows(IllegalArgumentException.class, () -> doc.localInsert(-1, "Test"));
|
||||
assertThrows(IllegalArgumentException.class, () -> doc.localInsert(6, "Test"));
|
||||
@ -31,7 +31,7 @@ public class DocumentTest {
|
||||
|
||||
@Test
|
||||
public void testLocalDelete() {
|
||||
SharedDocument doc = new SharedDocument(new DummyConnection());
|
||||
SharedDocument doc = new SharedDocument(new DummyConnection(), "test");
|
||||
doc.localInsert(0, "Hello World!");
|
||||
doc.localDelete(5, 6);
|
||||
assertEquals("Hello!", doc.getContents());
|
||||
@ -39,7 +39,7 @@ public class DocumentTest {
|
||||
|
||||
@Test
|
||||
public void testLocalDeleteInvalidIndexFails() {
|
||||
SharedDocument doc = new SharedDocument(new DummyConnection());
|
||||
SharedDocument doc = new SharedDocument(new DummyConnection(), "test");
|
||||
doc.localInsert(0, "Hello World!");
|
||||
assertThrows(IllegalArgumentException.class, () -> doc.localDelete(-1, 10));
|
||||
assertThrows(IllegalArgumentException.class, () -> doc.localDelete(12, 1));
|
||||
|
Loading…
Reference in New Issue
Block a user