From 734505066f8255e70c12f5b58e0ec12707ae899a Mon Sep 17 00:00:00 2001 From: Steven Tracey Date: Tue, 16 Jan 2024 10:19:22 -0600 Subject: [PATCH] Overhaul protocol --- build.gradle | 2 +- .../tech/nevets/dliteserver/Connection.java | 53 ++++++++++-- .../dliteserver/MessageDistributer.java | 86 +++++++++++++++---- 3 files changed, 119 insertions(+), 22 deletions(-) diff --git a/build.gradle b/build.gradle index 393c4c7..21a882c 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { } group = 'tech.nevets' -version = '1.1.0' +version = '1.2.0' repositories { mavenCentral() diff --git a/src/main/java/tech/nevets/dliteserver/Connection.java b/src/main/java/tech/nevets/dliteserver/Connection.java index 55307f6..c473d15 100644 --- a/src/main/java/tech/nevets/dliteserver/Connection.java +++ b/src/main/java/tech/nevets/dliteserver/Connection.java @@ -4,33 +4,64 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; public class Connection implements Runnable { + private Socket s; private InputStream is; private OutputStream os; private MessageDistributer md; private String username; public Connection(Socket s, MessageDistributer md) throws IOException { + this.s = s; this.is = s.getInputStream(); this.os = s.getOutputStream(); this.md = md; String buf = ""; - for (int i = is.read(); (char) i != '\n' && i != -1; i = is.read()) { + if (is.read() != 0x1) throw new IOException("Unexpected Command"); + for (int i = is.read(); i != 0xf && i != -1; i = is.read()) { buf += (char) i; } - username = buf; + username = buf.replace("\r", "").replace("\n", "").trim(); } @Override public void run() { + md.registerStream(this); + byte[] buf = new byte[1024]; + try { - md.registerStream(this); - is.transferTo(md); + loop: while (!s.isClosed()) { + byte cmd = (byte) is.read(); + int i = 0; + for (byte b = (byte) is.read(); b != 0xf && i < 1023; b = (byte) is.read()) { + buf[i] = b; + i++; + } + + switch (cmd) { + case 0x1 -> md.sendUserConnect(new String(Arrays.copyOfRange(buf, 0, i))); // User Connect + case 0x2 -> { + MessageDistributer.closeUserConnection(this); + md.sendUserDisconnect(new String(Arrays.copyOfRange(buf, 0, i))); // User Disconnect + break loop; + } + case 0x3 -> md.sendMessage(username, new String(Arrays.copyOfRange(buf, 0, i))); // Send Message + } + } + if (!s.isClosed()) { + try { + s.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } } catch (IOException e) { - System.out.println("Connection Disconnected"); + System.out.println("Connection disconnected unexpectedly"); + MessageDistributer.closeUserConnection(this); } - MessageDistributer.closeUserConnection(this); } public String getUsername() { @@ -44,4 +75,14 @@ public class Connection implements Runnable { public void updateUsername(String username) { this.username = username; } + + public void sendOnline(String onlineList) { + try { + os.write(0x4); + os.write(onlineList.getBytes(StandardCharsets.UTF_8)); + os.write(0xf); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/tech/nevets/dliteserver/MessageDistributer.java b/src/main/java/tech/nevets/dliteserver/MessageDistributer.java index 89b8033..42c3f17 100644 --- a/src/main/java/tech/nevets/dliteserver/MessageDistributer.java +++ b/src/main/java/tech/nevets/dliteserver/MessageDistributer.java @@ -5,40 +5,85 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.*; +/* +Commands: + - 0x1: User connect + - 0x2: User disconnect + - 0x3: Message + - 0x4: Online List + + - 0xff: End of PDU + + Usable: 00 - 1f, 80 - ff + */ + public class MessageDistributer extends OutputStream { private static List userStreams = new ArrayList<>(); private static MessageDistributer instance; - private String buf = ""; + private byte[] buf = new byte[1024]; + private short bufPointer = 0; public MessageDistributer() { instance = this; } @Override - public void write(int b) throws IOException { - buf += (char) b; - if (((char) b) == '\n') this.flush(); + public void write(int b) { + buf[bufPointer] = ((byte) b); + bufPointer++; + } + + public void write(byte[] b, int off, int len) throws IOException { + for (int i = 0 ; i < len; i++) { + write(b[off + i]); + } + flush(); } @Override public void flush() { for (Connection conn : userStreams) { try { - conn.getOutputStream().write((conn.getUsername() + "> " + buf).getBytes(StandardCharsets.UTF_8)); + System.out.println("Sending to: " + conn.getUsername()); + conn.getOutputStream().write(Arrays.copyOfRange(buf, 0, bufPointer)); + conn.getOutputStream().flush(); } catch (IOException e) { e.printStackTrace(); } } - buf = ""; + bufPointer = 0; } - private void writeSystem(String message) { - for (Connection conn : userStreams) { - try { - conn.getOutputStream().write(("SERVER> " + message + "\n").getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - e.printStackTrace(); - } + public void sendUserConnect(String user) { + try { + this.write(0x1); + this.write((user + "\r\n").getBytes(StandardCharsets.UTF_8)); + this.write(0xf); + this.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void sendUserDisconnect(String user) { + try { + this.write(0x2); + this.write((user + "\r\n").getBytes(StandardCharsets.UTF_8)); + this.write(0xf); + this.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void sendMessage(String user, String message) { + try { + this.write(0x3); + this.write((user + "> " + message).getBytes(StandardCharsets.UTF_8)); + this.write(0xf); + this.flush(); + } catch (IOException e) { + e.printStackTrace(); } } @@ -49,8 +94,18 @@ public class MessageDistributer extends OutputStream { i++; } conn.updateUsername(username); + sendUserConnect(username); userStreams.add(conn); - writeSystem("Welcome " + username + "!"); + conn.sendOnline(getOnlineList()); + sendMessage("SERVER", "Welcome " + username + "!\r\n"); + } + + private String getOnlineList() { + StringBuilder sb = new StringBuilder(); + for (Connection c : userStreams) { + sb.append(c.getUsername()).append("\n"); + } + return sb.toString(); } private boolean existingUsername(String username) { @@ -66,6 +121,7 @@ public class MessageDistributer extends OutputStream { public static void closeUserConnection(Connection conn) { userStreams.remove(conn); - getInstance().writeSystem(("Goodbye, " + conn.getUsername() + "!")); + getInstance().sendUserDisconnect(conn.getUsername()); + getInstance().sendMessage("SERVER", ("Goodbye, " + conn.getUsername() + "!\r\n")); } }