From ca562e90c1a7cab57f63a5f19b15ff3e9da18e7f Mon Sep 17 00:00:00 2001 From: RoyceDa Date: Mon, 2 Feb 2026 00:37:31 +0200 Subject: [PATCH] init --- .vscode/settings.json | 14 ++ pom.xml | 28 +++ src/main/java/com/rosetta/im/Main.java | 20 ++ .../java/com/rosetta/im/device/Device.java | 39 ++++ .../im/executors/Executor0Handshake.java | 13 ++ .../rosetta/im/packet/Packet0Handshake.java | 83 ++++++++ .../im/packet/enums/HandshakeStage.java | 36 ++++ .../java/com/rosetta/im/protocol/Client.java | 46 +++++ .../java/com/rosetta/im/protocol/Server.java | 70 +++++++ .../java/com/rosetta/im/protocol/Stream.java | 179 ++++++++++++++++++ .../rosetta/im/protocol/packet/Packet.java | 31 +++ .../im/protocol/packet/PacketExecutor.java | 5 + .../im/protocol/packet/PacketManager.java | 35 ++++ .../rosetta/im/protocol/util/StringUtil.java | 15 ++ target/classes/com/rosetta/im/Main.class | Bin 0 -> 996 bytes .../com/rosetta/im/device/Device.class | Bin 0 -> 1064 bytes .../im/executors/Executor0Handshake.class | Bin 0 -> 710 bytes .../rosetta/im/packet/Packet0Handshake.class | Bin 0 -> 1832 bytes .../im/packet/enums/HandshakeStage.class | Bin 0 -> 2092 bytes .../com/rosetta/im/protocol/Client.class | Bin 0 -> 1783 bytes .../com/rosetta/im/protocol/Server.class | Bin 0 -> 3828 bytes .../com/rosetta/im/protocol/Stream.class | Bin 0 -> 5109 bytes .../rosetta/im/protocol/packet/Packet.class | Bin 0 -> 511 bytes .../im/protocol/packet/PacketExecutor.class | Bin 0 -> 275 bytes .../im/protocol/packet/PacketManager.class | Bin 0 -> 2462 bytes .../rosetta/im/protocol/util/StringUtil.class | Bin 0 -> 956 bytes 26 files changed, 614 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 pom.xml create mode 100644 src/main/java/com/rosetta/im/Main.java create mode 100644 src/main/java/com/rosetta/im/device/Device.java create mode 100644 src/main/java/com/rosetta/im/executors/Executor0Handshake.java create mode 100644 src/main/java/com/rosetta/im/packet/Packet0Handshake.java create mode 100644 src/main/java/com/rosetta/im/packet/enums/HandshakeStage.java create mode 100644 src/main/java/com/rosetta/im/protocol/Client.java create mode 100644 src/main/java/com/rosetta/im/protocol/Server.java create mode 100644 src/main/java/com/rosetta/im/protocol/Stream.java create mode 100644 src/main/java/com/rosetta/im/protocol/packet/Packet.java create mode 100644 src/main/java/com/rosetta/im/protocol/packet/PacketExecutor.java create mode 100644 src/main/java/com/rosetta/im/protocol/packet/PacketManager.java create mode 100644 src/main/java/com/rosetta/im/protocol/util/StringUtil.java create mode 100644 target/classes/com/rosetta/im/Main.class create mode 100644 target/classes/com/rosetta/im/device/Device.class create mode 100644 target/classes/com/rosetta/im/executors/Executor0Handshake.class create mode 100644 target/classes/com/rosetta/im/packet/Packet0Handshake.class create mode 100644 target/classes/com/rosetta/im/packet/enums/HandshakeStage.class create mode 100644 target/classes/com/rosetta/im/protocol/Client.class create mode 100644 target/classes/com/rosetta/im/protocol/Server.class create mode 100644 target/classes/com/rosetta/im/protocol/Stream.class create mode 100644 target/classes/com/rosetta/im/protocol/packet/Packet.class create mode 100644 target/classes/com/rosetta/im/protocol/packet/PacketExecutor.class create mode 100644 target/classes/com/rosetta/im/protocol/packet/PacketManager.class create mode 100644 target/classes/com/rosetta/im/protocol/util/StringUtil.class diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f8f0c7b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/.DS_Store": true, + "**/Thumbs.db": true, + ".DS_Store": true, + "._*": true, + "**/._*": true + }, + "java.project.explorer.showNonJavaResources": false, + "java.configuration.updateBuildConfiguration": "interactive" +} \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..19b9e3e --- /dev/null +++ b/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + com.rosetta.im + rosetta-server + 1.0-SNAPSHOT + + + 17 + 17 + + + + + + + + + org.java-websocket + Java-WebSocket + 1.6.0 + + + + \ No newline at end of file diff --git a/src/main/java/com/rosetta/im/Main.java b/src/main/java/com/rosetta/im/Main.java new file mode 100644 index 0000000..f09e66a --- /dev/null +++ b/src/main/java/com/rosetta/im/Main.java @@ -0,0 +1,20 @@ +package com.rosetta.im; + + +import com.rosetta.im.packet.Packet0Handshake; +import com.rosetta.im.protocol.Server; +import com.rosetta.im.protocol.packet.PacketManager; + +public class Main { + public static void main(String[] args) { + PacketManager manager = new PacketManager(); + manager.registerPacket(0, Packet0Handshake.class); + + + Server server = new Server(8881, manager); + server.start(); + + + System.out.println("Rosetta server started..."); + } +} \ No newline at end of file diff --git a/src/main/java/com/rosetta/im/device/Device.java b/src/main/java/com/rosetta/im/device/Device.java new file mode 100644 index 0000000..e3ebfb9 --- /dev/null +++ b/src/main/java/com/rosetta/im/device/Device.java @@ -0,0 +1,39 @@ +package com.rosetta.im.device; + +public class Device { + + public String deviceId; + public String deviceName; + public String deviceOs; + + public Device(String deviceId, String deviceName, String deviceOs) { + this.deviceId = deviceId; + this.deviceName = deviceName; + this.deviceOs = deviceOs; + } + + public String getDeviceId() { + return deviceId; + } + + public String getDeviceName() { + return deviceName; + } + + public String getDeviceOs() { + return deviceOs; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + public void setDeviceOs(String deviceOs) { + this.deviceOs = deviceOs; + } + +} diff --git a/src/main/java/com/rosetta/im/executors/Executor0Handshake.java b/src/main/java/com/rosetta/im/executors/Executor0Handshake.java new file mode 100644 index 0000000..349fab1 --- /dev/null +++ b/src/main/java/com/rosetta/im/executors/Executor0Handshake.java @@ -0,0 +1,13 @@ +package com.rosetta.im.executors; + +import com.rosetta.im.protocol.packet.Packet; +import com.rosetta.im.protocol.packet.PacketExecutor; + +public class Executor0Handshake implements PacketExecutor { + + @Override + public void onPacketReceived(Class packet) { + + } + +} diff --git a/src/main/java/com/rosetta/im/packet/Packet0Handshake.java b/src/main/java/com/rosetta/im/packet/Packet0Handshake.java new file mode 100644 index 0000000..6389fce --- /dev/null +++ b/src/main/java/com/rosetta/im/packet/Packet0Handshake.java @@ -0,0 +1,83 @@ +package com.rosetta.im.packet; + +import com.rosetta.im.device.Device; +import com.rosetta.im.packet.enums.HandshakeStage; +import com.rosetta.im.protocol.Stream; +import com.rosetta.im.protocol.packet.Packet; + +/** + * Пакет хэндшейка между клиентом и сервером. + * Используется для установления соединения и подтверждения от сервера что клиент + * тот за кого себя выдает. + * + * Протокол таблица: + * 0 - packetId (int16) + * 1 - privateKey (string) + * 2 - publicKey (string) + * 3 - protocolVersion (int8) + * 4 - heartbeatInterval (int8) + * 5 - deviceId (string) + * 6 - deviceName (string) + * 7 - deviceOs (string) + * 8 - handshakeStage (int8) + */ +public class Packet0Handshake extends Packet { + /** + * Публичный и приватный ключи клиента + */ + private String publicKey; + private String privateKey; + /** + * Версия протокола клиента + */ + private int protocolVersion = 1; + + /** + * Интервал отправки heartbeat пакетов в секундах + */ + private int heartbeatInterval = 15; + + /** + * Минимальная информация об устройстве клиента + */ + private Device device; + + /** + * Стадия рукопожатия + * 0 - COMPLETED + * 1 - NEED_DEVICE_VERIFICATION + */ + private HandshakeStage handshakeStage = HandshakeStage.COMPLETED; + + + @Override + public Stream write() { + Stream stream = new Stream(); + stream.writeInt16(this.packetId); + stream.writeString(this.privateKey); + stream.writeString(this.publicKey); + stream.writeInt8(this.protocolVersion); + stream.writeInt8(this.heartbeatInterval); + stream.writeString(this.device.getDeviceId()); + stream.writeString(this.device.getDeviceName()); + stream.writeString(this.device.getDeviceOs()); + stream.writeInt8(this.handshakeStage.getCode()); + return stream; + } + + @Override + public void read(Stream stream) { + this.privateKey = stream.readString(); + this.publicKey = stream.readString(); + this.protocolVersion = stream.readInt8(); + this.heartbeatInterval = stream.readInt8(); + String deviceId = stream.readString(); + String deviceName = stream.readString(); + String deviceOs = stream.readString(); + this.device = new Device(deviceId, deviceName, deviceOs); + this.handshakeStage = HandshakeStage.fromCode( + stream.readInt8() + ); + } + +} diff --git a/src/main/java/com/rosetta/im/packet/enums/HandshakeStage.java b/src/main/java/com/rosetta/im/packet/enums/HandshakeStage.java new file mode 100644 index 0000000..a581057 --- /dev/null +++ b/src/main/java/com/rosetta/im/packet/enums/HandshakeStage.java @@ -0,0 +1,36 @@ +package com.rosetta.im.packet.enums; + +/** + * Этапы хэндшейка между клиентом и сервером. + */ +public enum HandshakeStage { + /** + * Успешный хэндшейк + * Такой пользователь может авторизованно взаимодействовать с сервером + */ + COMPLETED(0), + /** + * Необходима верификация устройства + * Такой пользователь должен подтвердить устройство (например, через код на другом устройстве) + */ + NEED_DEVICE_VERIFICATION(1); + + private final int code; + + HandshakeStage(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + + public static HandshakeStage fromCode(int code) { + for (HandshakeStage stage : HandshakeStage.values()) { + if (stage.getCode() == code) { + return stage; + } + } + throw new IllegalArgumentException("Invalid HandshakeStage code: " + code); + } +} diff --git a/src/main/java/com/rosetta/im/protocol/Client.java b/src/main/java/com/rosetta/im/protocol/Client.java new file mode 100644 index 0000000..58b04a0 --- /dev/null +++ b/src/main/java/com/rosetta/im/protocol/Client.java @@ -0,0 +1,46 @@ +package com.rosetta.im.protocol; + +import java.util.HashMap; +import java.util.Map; + +import org.java_websocket.WebSocket; + +import com.rosetta.im.protocol.util.StringUtil; + +public class Client { + + public WebSocket socket; + public String clientId; + public Map clientData; + + public Client(WebSocket socket) { + this.socket = socket; + this.clientId = StringUtil.randomString(32); + this.clientData = new HashMap<>(); + } + + public String getClientId() { + return clientId; + } + + public Map getClientData() { + return clientData; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public void setData(String key, Object value) { + this.clientData.put(key, value); + } + + public void setData(Map data) { + this.clientData = data; + } + + public Object getData(String key) { + return this.clientData.get(key); + } + +} diff --git a/src/main/java/com/rosetta/im/protocol/Server.java b/src/main/java/com/rosetta/im/protocol/Server.java new file mode 100644 index 0000000..f1bfaf0 --- /dev/null +++ b/src/main/java/com/rosetta/im/protocol/Server.java @@ -0,0 +1,70 @@ +package com.rosetta.im.protocol; + +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; + +import org.java_websocket.WebSocket; +import org.java_websocket.handshake.ClientHandshake; +import org.java_websocket.server.WebSocketServer; + +import com.rosetta.im.protocol.packet.Packet; +import com.rosetta.im.protocol.packet.PacketManager; + +public class Server extends WebSocketServer { + + private PacketManager packetManager; + + public Server(int port, PacketManager packetManager) { + super(new InetSocketAddress(port)); + this.packetManager = packetManager; + } + + @Override + public void onClose(WebSocket arg0, int arg1, String arg2, boolean arg3) { + + } + + @Override + public void onError(WebSocket arg0, Exception arg1) { + + } + + @Override + public void onMessage(WebSocket arg0, String arg1) { + + } + + @Override + public void onMessage(WebSocket socket, ByteBuffer byteBuffer) { + Client client = socket.getAttachment(); + + byte[] bytes = byteBuffer.array(); + Stream stream = new Stream(bytes); + int packetId = stream.readInt16(); + Class packetClass = this.packetManager.getPacketClass(packetId); + if(packetClass == null){ + System.out.println("Received unknown packet with id: " + packetId); + return; + } + try { + Packet packet = packetClass.getConstructor().newInstance(); + packet.packetId = packetId; + packet.read(stream); + System.out.println("Received packet: " + packetClass.getSimpleName()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onOpen(WebSocket socket, ClientHandshake arg1) { + Client client = new Client(socket); + socket.setAttachment(client); + } + + @Override + public void onStart() { + + } + +} diff --git a/src/main/java/com/rosetta/im/protocol/Stream.java b/src/main/java/com/rosetta/im/protocol/Stream.java new file mode 100644 index 0000000..b54ee64 --- /dev/null +++ b/src/main/java/com/rosetta/im/protocol/Stream.java @@ -0,0 +1,179 @@ +package com.rosetta.im.protocol; + +public class Stream { + + private byte[] stream; + private int readPointer = 0; + private int writePointer = 0; + + public Stream() { + this.stream = new byte[0]; + } + + public Stream(byte[] stream) { + this.stream = stream; + } + + public byte[] getStream() { + return this.stream; + } + + public void setStream(byte[] stream) { + this.stream = stream; + } + + public void writeInt8(int value) { + int negationBit = value < 0 ? 1 : 0; + int int8Value = Math.abs(value) & 0xFF; + + ensureCapacity(writePointer >> 3); + stream[writePointer >> 3] |= (byte)(negationBit << (7 - (writePointer & 7))); + writePointer++; + + for (int i = 0; i < 8; i++) { + int bit = (int8Value >> (7 - i)) & 1; + ensureCapacity(writePointer >> 3); + stream[writePointer >> 3] |= (byte)(bit << (7 - (writePointer & 7))); + writePointer++; + } + } + + public int readInt8() { + int value = 0; + int negationBit = (stream[readPointer >> 3] >> (7 - (readPointer & 7))) & 1; + readPointer++; + + for (int i = 0; i < 8; i++) { + int bit = (stream[readPointer >> 3] >> (7 - (readPointer & 7))) & 1; + value |= bit << (7 - i); + readPointer++; + } + + return negationBit == 1 ? -value : value; + } + + public void writeBit(int value) { + int bit = value & 1; + ensureCapacity(writePointer >> 3); + stream[writePointer >> 3] |= (byte)(bit << (7 - (writePointer & 7))); + writePointer++; + } + + public int readBit() { + int bit = (stream[readPointer >> 3] >> (7 - (readPointer & 7))) & 1; + readPointer++; + return bit; + } + + public void writeBoolean(boolean value) { + writeBit(value ? 1 : 0); + } + + public boolean readBoolean() { + return readBit() == 1; + } + + public void writeInt16(int value) { + writeInt8(value >> 8); + writeInt8(value & 0xFF); + } + + public int readInt16() { + int value = readInt8() << 8; + return value | readInt8(); + } + + public void writeInt32(int value) { + writeInt16(value >> 16); + writeInt16(value & 0xFFFF); + } + + public int readInt32() { + int value = readInt16() << 16; + return value | readInt16(); + } + + public void writeInt64(long value) { + int high = (int)(value >> 32); + int low = (int)value; + writeInt32(high); + writeInt32(low); + } + + public long readInt64() { + long high = readInt32(); + long low = readInt32() & 0xFFFFFFFFL; + return (high << 32) | low; + } + + public void writeFloat32(float value) { + int floatValue = Float.floatToIntBits(value); + writeInt32(floatValue); + } + + public float readFloat32() { + int floatValue = readInt32(); + return Float.intBitsToFloat(floatValue); + } + + public void writeString(String value) { + int length = value.length(); + writeInt32(length); + for (int i = 0; i < value.length(); i++) { + writeInt16(value.charAt(i)); + } + } + + public String readString() { + int length = readInt32(); + + // Security fix for string length exceeding stream capacity + if (length < 0 || length > (stream.length - (readPointer >> 3))) { + System.out.println("Stream readString length invalid: " + length + ", stream length: " + stream.length + ", readPointer: " + readPointer); + return ""; + } + + StringBuilder value = new StringBuilder(); + for (int i = 0; i < length; i++) { + value.append((char)readInt16()); + } + return value.toString(); + } + + public void writeBytes(byte[] value) { + writeInt32(value.length); + for (int i = 0; i < value.length; i++) { + writeInt8(value[i]); + } + } + + public byte[] readBytes() { + int length = readInt32(); + byte[] value = new byte[length]; + for (int i = 0; i < length; i++) { + value[i] = (byte)readInt8(); + } + return value; + } + + public boolean isEmpty() { + return this.stream.length == 0; + } + + public int length() { + return this.stream.length; + } + + public byte[] getBuffer() { + return this.stream; + } + + private void ensureCapacity(int byteIndex) { + if (byteIndex >= stream.length) { + byte[] newStream = new byte[byteIndex + 1]; + System.arraycopy(stream, 0, newStream, 0, stream.length); + stream = newStream; + } + } + +} diff --git a/src/main/java/com/rosetta/im/protocol/packet/Packet.java b/src/main/java/com/rosetta/im/protocol/packet/Packet.java new file mode 100644 index 0000000..bb74db9 --- /dev/null +++ b/src/main/java/com/rosetta/im/protocol/packet/Packet.java @@ -0,0 +1,31 @@ +package com.rosetta.im.protocol.packet; + +import com.rosetta.im.protocol.Stream; + +/** + * Представляет собой абстрактный класс для всех пакетов, используемых в протоколе. + */ +public abstract class Packet { + + public int packetId; + public PacketManager packetManager; + + public Packet() { + + } + + /** + * Записывает данные пакета в поток. Исползуется при отправке + * + * @return Поток с записанными данными пакета. + */ + public abstract Stream write(); + + /** + * Читает данные пакета из потока. Используется при получении + * + * @param stream Поток с данными пакета. + */ + public abstract void read(Stream stream); + +} diff --git a/src/main/java/com/rosetta/im/protocol/packet/PacketExecutor.java b/src/main/java/com/rosetta/im/protocol/packet/PacketExecutor.java new file mode 100644 index 0000000..bca1a0a --- /dev/null +++ b/src/main/java/com/rosetta/im/protocol/packet/PacketExecutor.java @@ -0,0 +1,5 @@ +package com.rosetta.im.protocol.packet; + +public interface PacketExecutor { + public void onPacketReceived(Class packet); +} diff --git a/src/main/java/com/rosetta/im/protocol/packet/PacketManager.java b/src/main/java/com/rosetta/im/protocol/packet/PacketManager.java new file mode 100644 index 0000000..cabd5dd --- /dev/null +++ b/src/main/java/com/rosetta/im/protocol/packet/PacketManager.java @@ -0,0 +1,35 @@ +package com.rosetta.im.protocol.packet; + +import java.util.HashMap; + +public class PacketManager { + + private HashMap> packets; + + public PacketManager() { + this.packets = new HashMap<>(); + } + + public void registerPacket(int packetId, Class packet) { + this.packets.put(packetId, packet); + } + + public boolean isPacketRegistred(Packet packet) { + return this.packets.containsValue(packet.getClass()); + } + + public Integer getPacketIdByClass(Class packetClass) { + for (var entry : this.packets.entrySet()) { + if (entry.getValue().equals(packetClass)) { + return entry.getKey(); + } + } + return null; + } + + public Class getPacketClass(int packetId) { + return this.packets.get(packetId); + } + + +} diff --git a/src/main/java/com/rosetta/im/protocol/util/StringUtil.java b/src/main/java/com/rosetta/im/protocol/util/StringUtil.java new file mode 100644 index 0000000..877f270 --- /dev/null +++ b/src/main/java/com/rosetta/im/protocol/util/StringUtil.java @@ -0,0 +1,15 @@ +package com.rosetta.im.protocol.util; + +public class StringUtil { + + public static String randomString(int length) { + StringBuilder sb = new StringBuilder(); + String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + for (int i = 0; i < length; i++) { + int index = (int) (Math.random() * characters.length()); + sb.append(characters.charAt(index)); + } + return sb.toString(); + } + +} diff --git a/target/classes/com/rosetta/im/Main.class b/target/classes/com/rosetta/im/Main.class new file mode 100644 index 0000000000000000000000000000000000000000..33955d8f21ce53ba53052ecf16f68be8b5e93ec1 GIT binary patch literal 996 zcmb7DU2hUW6g|U77uK~z53)Nn(SKDR zAhC%*z#nD2yQ`KG`rymlot?Soo_o%npTEBU0PqSg6eJjmrso*G7YHf2VL3*JTdsl> zL;i%Hal_{B(D=|l5vF8VdTF_qe9e%o)q4!718*QyB$3sS#u7uWZMow8*y#)Z6YtxC zq0shBZuhuvh5J80Q}Wmf7)tF0rCS8+5Cw+S+UNEqg|751ci5`;6s#~b=Q2mWCq2`% zjS)9bg)|PM(BUp03SUJYSp~Nkw&&AkZ|}Y3?jShkr_@p&s~T?O4#To9hE^bjA43xB z+PfKA2R09ah}9ay`aJw!R$bwrg*?i*8!B~=VV_X0yS=CfDiNk{XsCulrvu4-nZ*_! zD7b&ctL_(K>u7k0ZSu(*lWnD#u;m$tB%&lK1$SB*)ELSiW9O?uM6nv-ih-`{Dt6IS z(4Yy4T)3L8;SqEOWfTJ1e%v?{bSC^Cxa-6=BX(XmQvcnoB4gH|oR zK=CH+vRFor{)EY2k%~ZT7sww?=>as7h2jLI3zUymw$2+< u0BTerM~D@|+&}?4C`L7_F)q>Dqk9>egvZ#Ysukk!1W%(Tp3zAH&wm4p#r2~A literal 0 HcmV?d00001 diff --git a/target/classes/com/rosetta/im/device/Device.class b/target/classes/com/rosetta/im/device/Device.class new file mode 100644 index 0000000000000000000000000000000000000000..f6959d71e2900d19f8842a0dc40d2fb6fe4e3b31 GIT binary patch literal 1064 zcma)3+fLg+5Ivh1hd2%)7bvvhl3t|56#QJZ<)sx;r3fCV^6ogRbWsvZ#_(N5BC6B} zKA<0knAx?QDj3Ae&SmGEnK|?C{_h=tuXtBNL7*K*Q$LO_Ws(HGn))MotwQO4*QNwZ zVErPv4*W?l8~bO&3mGN?tETG5NTAVQe4i(=nvFjTIOhK}n98j9>{7t~qGl>N7WmYC z40}nYHxRJCMI-5;h^mV+)&z>(-k=N`)Wr&H_8Klq#%sA)g)LC)tC>8#nhs_BGZ;>2 ztVTZygUKL>6~}4PN`5JtbGQGTDzso_EE6LUYtZWU9uF^2&5Dc=3lM8jA;}jM8##jT zvem3A<;Y^@aL%KvIFu)f7pfSxBfbYZq(YI-TqH}PkSACYZAlQaCCZfH&|9Hsf&whE zE$K8cQ{A$hVlh$(7Q=oAe2S8GU3+XqKPWy0ngy^3R@HrlkO|D$DIq> zj1Ar7?o5375~(o*C`={Av+h+zPkv55-uf zkYLyyiMim8a0mRpHm@q@-Q}^~-`@dAwNrQHyfgYtT z)m-)&O4asCSj!QqZN2gDy6er5%!(d^p|H`5q5M2!qmJ3+z^gK|FW6&n(OVXbaBTqXZo2HDDXXKNoZ^*oc$2qcA z2wK>tI2RRQ2YJfqbx|OaVpzKulH7zbodpDOy09e3h6H6Q4=zRoK~%y%*)pLKd4N<1 KVK^WxhQn{P*s+2D literal 0 HcmV?d00001 diff --git a/target/classes/com/rosetta/im/packet/Packet0Handshake.class b/target/classes/com/rosetta/im/packet/Packet0Handshake.class new file mode 100644 index 0000000000000000000000000000000000000000..20b0d02a2d155039ecf7a9cb72e94b58b32c8374 GIT binary patch literal 1832 zcmah}YgZdp6x}yT^XhGBDNVsXtW_`xl%d!M5a>f5B_$*v7)5J!l8i7m57uPB<-byw z30>`4e%Bx6a-W%@t|V5!+;i@|=dsT@``$nQdi^_qB~)SvDNIyb4Z~@*E!Q;-yI~xf z)t8oQYh2g>v=CNti&E~$b z<2rV8Kc|p9bnIi(wLFWV!yruAa@uyQsi5)-7Y{7caVwVT=9{kN9Gi88Xw5pdtCqrz zLLUzeiA~)jVpnjkjfb*7T1q+D+Sis1QzP$_kO?R?SKx zj7u6rxR8LtWsNuzqFvEQiZ+I;F}$ac?ZfsTnKZ89Jo~j=+T1Fv?yjy#yc-(l>nhHJM*Jsy9{?Lof&XCohV0T znT=cw69m*>P_I!Enoy%F&dBY zgt_-E*QZdvrZB?x3~*NhE^Dla`MI~|MYBPAEMZOKX>XuXJ4s^XHJ)KZAx00OlE*8O zJlgi!tZ?)H2Em?jAVl@y;GlcQk;{~&pW7Or36!L``R$bBU5(ELNnDOOjX8n+g|PZd zh53K!_FxMJPbA|QzS8&_&l&oAr`7PQG&tvh%KQ)J9S<+=&qey5^i}CCgZi5inV#Hf z9XVBN&6X!|xu4(DGBSKX288*`MG+F3PzwpsJjrM4Nj_Rnk|v(yqoWMdlTV!MMeerg zrzo#vPcWQ~bTE>=Fw{XR`zuB}xc-ah_&(PZ(*UE0Fm(bG3^B{IQQYLI_CxUI7Iz#W zJ_^FWX7~`#UcABh-U&V~OlE&Wx{FDXMi+NP-V5YN7Y}5g3gki;i@_DuPybO@1NC|r z>tg#eGlU>0r}-v;2mHC_SmHeKEf8T2X)I!fM9ASG*6@gBKgM%B@zAGygaP_E$|zuy z_!WvM1$F$v)=K>w*~u=pIxqrxPvnkt&6g>;-jt;%%R(gk21|QWx5pwUD0i^nnZ3eZ zPitqr`K%H2Q-WS6=sbZvBbhh&-xLUZlaPyqT;jVd@@Crue%FT-04KNr_&CS&jmL~E W?_N*~GsabXOD)2JzGERFn12I&2df$Y literal 0 HcmV?d00001 diff --git a/target/classes/com/rosetta/im/packet/enums/HandshakeStage.class b/target/classes/com/rosetta/im/packet/enums/HandshakeStage.class new file mode 100644 index 0000000000000000000000000000000000000000..4bec1d760256b66c4e04b7625c499fcae58beeb2 GIT binary patch literal 2092 zcmb7EQBxaL6#g!oWRtK3Od&KBT12W4pxdIY3KXGXk+lib2GYs&p~0u& z_t|G3^~o0>Dz(D2Bl_%b@i$n{-9)oY(Gh0C?!Eh+@0{;D=icA{e0c)k4j#(rV#phA zUG-ew3<9oNb+y5bJu^^Er&;&aHSX;AyL`_q2fSv=h%xj$<@;Qa$!Z4%?8>Rb2 zZBtuem@fW*wt0q2>zcOmctxw|1?_P~d!VoCh2>3sW1S&pxH~2T(;2$8^{vu)Wx2Se zl^JFpoi9gn!LTjI3KkipiOC8v7l=8Dcp40EDaha=Lt>!~8Js9~^pyk8a%%IsK3Pc- zctAlMi6msPxTHWvLc9$rNTZvfw`e)$db7T5dYgRPrs6Y2*Wh-AdzM&-n`ub6B9dNZ z$exv}mFjH;Nu;ROVAt{)|9ugg$v5Lxk!H1(V2=>V0lEP2yK4 zCeP)nAemP14#s6%XBg{PrrWkzTYf}5CS7_8Gk6VeP8V z*%b+Q6?}pM!>uS;!REd{AF1FU_Kq5H3`t+Q>^42aT(!jLT|9kquM0FuEn78*2ThL< zixE=6uyCF!S`>cXb=|-ZJl-go!LGaGr|}tzGVU>qcZ#!|eRt1PTV=PJzRHcj^$x@| zlo-B=%59@tghGOC`r}2{-D@_^Fd?GgRN&@8!#o52D1vV{GCFN-iUPOovK5%~y$R?^ z+-JC=JJe}wXY{nEqvD2|8)XcN?l`6ww#xKnlo_tQVZd3EWNZ=pe?#e%w)8LEq(djs zF^Vna#61Mildd4z$%xAW=o=Cj5v>!nR&asvJ+%6Q(BkjLE3j&&SCWp<_Z9b{7|D;kz-Wi5Csfc+u>-`F4H>c&Pk4-lTEv@BBM~3nFKt$po{UiO{7)GDAxtX@ zON5)bkVa_%+B7L#!@IO24EUPJgaxz5c&|DaJ6V+Oe2;-#Yb?7Bj;0W*kN>Nh8f)NsW1w*(>8AqtNv50`#Ruc%3#_h1O4=FkW={0pC zPUSNh9|1jGB#v(1c5Sz*GSSrRA#&AwQvRg6AUaW!E+6CL>1Xt%)q<8%7UmOnrRc6$ xYIEcXBg{!>SpFExzk&UGTnsBAr-s$=`6<@unWXr2`fcEI!9#Bku!#zCe*w9z??eCq literal 0 HcmV?d00001 diff --git a/target/classes/com/rosetta/im/protocol/Client.class b/target/classes/com/rosetta/im/protocol/Client.class new file mode 100644 index 0000000000000000000000000000000000000000..0a642fbc8c791ab6797f18df97b5b592d8983c8b GIT binary patch literal 1783 zcma)7Yflk73QGliwWT6fD=+KzWwmOxt){67txae#{nRY5!Bt?%ve@{q+N8$X zCj9~ZQBCj6EU+RrhJ=~9bLY&t=iGrme}Dc4@EkhC8?O0Q5TBEA&l@9f?&ERjDG~#N_&1D(VQ(_brvJ}2Q)KXMn-x6>FQN*mYgEj-j5AE6cQY=wjvV}+I|>3A4j{o06?zH0H(Kj}6bWJ)QJyuc zU<5&~n9lUSjuZp#I?Y&<=H zB}2HIBz=o^(p=81^vAC4SBSc?M`0p;Sto8(fU@N6sR0?TGfpRDiXl9}qW~Tf|DLcU zs)EOOLPj^+)X=MLFz4t1u*)F=IMPoThK{vbTlmoHb_a*danQRu@k%;Zc7oRwN_1;Q zyqn33o}V;3z6Z!CDbj+wE~nkx-Z~VyMq3JA;3d^VhZ!y$>}WZt{9wUsTV?&V!MiXd z4P4?HV3r!zOFueZ8tDzujO@d(7^#bC6{5KZyz|K%+@SAKij?SthsH$q43TW^6l2*) z@&_hP5zqd@^rth-oFe&6oV`omlY|aL;6s#NM~psW^j^j>C-wvq=5dc!gejOXx@iF^ z=RTE2Mteiq?}&e;i3c3kFM?A7Mv(~)3_}_j%98Z6g0veX*$)yQ2$I7h!SaeX35@gf z^J?S0%7P*~L!6VYYW&@5{6bI8{yvr*tUXeXs~)CmlDWlms9x;%L(Y-t^8zv{le>^% zER#iCjxe5Lg$Qu)RT^cr&jjK3wC)lXR(OSGl5mO$r>`KqCX8Pve5t7)YhuQ*LH|xt fjx7g0BuY5PrU(6s=3MZhF8Po{p5YZ;;KBAkIp})! literal 0 HcmV?d00001 diff --git a/target/classes/com/rosetta/im/protocol/Server.class b/target/classes/com/rosetta/im/protocol/Server.class new file mode 100644 index 0000000000000000000000000000000000000000..ca113bb4a161398c4df983d06c2136df9fa0a937 GIT binary patch literal 3828 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 literal 0 HcmV?d00001 diff --git a/target/classes/com/rosetta/im/protocol/packet/Packet.class b/target/classes/com/rosetta/im/protocol/packet/Packet.class new file mode 100644 index 0000000000000000000000000000000000000000..d6c377d4effd030d22d4d3e610e2537e5e0a43b4 GIT binary patch literal 511 zcma)(OHTqZ5Xb+sEDskD#OGCw5j@a?M;{jx6O#3jV7Pae28+8}Qi^^qPbMDx0DdUr zEX&nMn#^ye{dcC*`TqI*0&s<@2{a%yi||fna-uAuAFh>srN1ClE_J5eHKEk)jR^jY8LI## zG#l7JKxlHBQuawki6V4D6U$^It0vd$~ZEPW*RtMWl?qHWs343fk?EeC5<$c5e literal 0 HcmV?d00001 diff --git a/target/classes/com/rosetta/im/protocol/packet/PacketExecutor.class b/target/classes/com/rosetta/im/protocol/packet/PacketExecutor.class new file mode 100644 index 0000000000000000000000000000000000000000..a4c2f31a87640ec9317fce5f4839f00db066516e GIT binary patch literal 275 zcma)%%?`mp6ot?DE47jE5JZ>kYshT?aLWiBxB5?`uTL!lB|iRH~wsm0eN+=iuLgS(rK{1p8I ze(^({sZ?~vamH`{0Dq44x%cjdMfw3gIGNeaJ@?$_Jm)#*p8e~eUw;R14G%1&1SV_E zos!=SWEeUncc--LH^XMF*(mKgwFfdRt?1XH<2iNdTSyD^Z95O0Qp54;rR9xnSqlX$ z;~WSKF6iA>=r&68PO!D;?3M+3R^7Vige_kR)Q)>h8ba>7(;I6*Kyv2Y@$ znbfvi|Gw49pMh`L;@&f(Gm}Zbewg&w#N7I8t8IOlD=f(sONx5cVoEhOAb zD1iD>gL>DMB`Et*04zOifbyca?J5Gjg{aYL#kxowecQUxo+u&{@$u&uk^>d z=*d7+xtAko)&j3+_V6Nd!^U;I&$BM?g%dV?)sPW)eYP6e2~fce3m;H|Lx6bK#!Y<4 zd+*6_8GR^5NKCD=1$N%x;ZcsNi#HVEUd-c`jRgguN~=p{VTtoVdutFas%nB28y~C6 zcFAvAP9so0|*YKHy_J4;N3c+Pl7h-&8|Ue!@@ zxP&o!7wBc;Doc?Tjyg>6sq(nawL-L2yor4<+-pB_ozl@%{=k5aG;I9Zk!+$};l99I zc$<4Bi+42YpIoPTa#o@4q-uP^acJF%~IVim5HT=}>>`*4_pBAQg}Y(lYon^-=o UO$t)`-$$Kq)lu`S$+a&p;SQ-jV7Q5f_R&3)?{I`8#fa~&sKT! z9XxrJOR%)c2k<$34zxE5MQJWpO?CJ5-+c3R|2+Bj1HgSO$_Oxw>rPd3ow^|e*UYL` za~yvs&Ej@h+br%Gx?t$MXWFJ%W(dX;1qLbYlnezy zgjIB)lc76n+QvqsS~T1(UbGB`o~)yDtH52;yPrBGQ8DWbiR^#ESz=IKZkL>@50RlS zo=IfS@%ip085bD(|8=i6OsizL3StO{(95vAvYK9du>SB-=JAtkZe#Q5v*-D(?ZVEB z-Iu(mmyB2Cin+IMRc)vC+O3Pm!JEUk@1|#F=Th?vi+AoSxP;3x`Wd>;pUQDjQ89o) zBFTr^B56&*5JqGS|3#+{SH)Faqjbx#%c9as&v@x$Dz4)O1@sDcSBQ0qKAZO7-%>G- zI7N7^X4oZ$p?JEThSUEpc@+~XCXr+a3FnNu-gtWn5zI0SfqIc)ppDnFh75`aiR;2} zX?#6xiC!C%p~JLG#vwyAFSx#+c+b1Ek?JG$J@3kk4B7wD4<;h0%XxT zk(BACk!GYjCXNw0YK0Y&UKmsmA*uQaq@#2TqYK^S@rsWiQ7a(z9kJbGg4}a47hL{~ z;jidRHgV;{{>KGrGTA3JG1|n