Merge pull request 'master' (#1) from master into main
Reviewed-on: http://172.86.92.132/Rosetta/rosetta-server/pulls/1
This commit is contained in:
14
.vscode/settings.json
vendored
Normal file
14
.vscode/settings.json
vendored
Normal file
@@ -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"
|
||||
}
|
||||
28
pom.xml
Normal file
28
pom.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.rosetta.im</groupId>
|
||||
<artifactId>rosetta-server</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
<version>1.6.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
20
src/main/java/com/rosetta/im/Main.java
Normal file
20
src/main/java/com/rosetta/im/Main.java
Normal file
@@ -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...");
|
||||
}
|
||||
}
|
||||
39
src/main/java/com/rosetta/im/device/Device.java
Normal file
39
src/main/java/com/rosetta/im/device/Device.java
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<? extends Packet> packet) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
83
src/main/java/com/rosetta/im/packet/Packet0Handshake.java
Normal file
83
src/main/java/com/rosetta/im/packet/Packet0Handshake.java
Normal file
@@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
46
src/main/java/com/rosetta/im/protocol/Client.java
Normal file
46
src/main/java/com/rosetta/im/protocol/Client.java
Normal file
@@ -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<String, Object> clientData;
|
||||
|
||||
public Client(WebSocket socket) {
|
||||
this.socket = socket;
|
||||
this.clientId = StringUtil.randomString(32);
|
||||
this.clientData = new HashMap<>();
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public Map<String, Object> 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<String, Object> data) {
|
||||
this.clientData = data;
|
||||
}
|
||||
|
||||
public Object getData(String key) {
|
||||
return this.clientData.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
70
src/main/java/com/rosetta/im/protocol/Server.java
Normal file
70
src/main/java/com/rosetta/im/protocol/Server.java
Normal file
@@ -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<? extends Packet> 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() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
179
src/main/java/com/rosetta/im/protocol/Stream.java
Normal file
179
src/main/java/com/rosetta/im/protocol/Stream.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
31
src/main/java/com/rosetta/im/protocol/packet/Packet.java
Normal file
31
src/main/java/com/rosetta/im/protocol/packet/Packet.java
Normal file
@@ -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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.rosetta.im.protocol.packet;
|
||||
|
||||
public interface PacketExecutor {
|
||||
public void onPacketReceived(Class <? extends Packet> packet);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.rosetta.im.protocol.packet;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class PacketManager {
|
||||
|
||||
private HashMap<Integer, Class<? extends Packet>> packets;
|
||||
|
||||
public PacketManager() {
|
||||
this.packets = new HashMap<>();
|
||||
}
|
||||
|
||||
public void registerPacket(int packetId, Class<? extends Packet> packet) {
|
||||
this.packets.put(packetId, packet);
|
||||
}
|
||||
|
||||
public boolean isPacketRegistred(Packet packet) {
|
||||
return this.packets.containsValue(packet.getClass());
|
||||
}
|
||||
|
||||
public Integer getPacketIdByClass(Class<? extends Packet> packetClass) {
|
||||
for (var entry : this.packets.entrySet()) {
|
||||
if (entry.getValue().equals(packetClass)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Class<? extends Packet> getPacketClass(int packetId) {
|
||||
return this.packets.get(packetId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
15
src/main/java/com/rosetta/im/protocol/util/StringUtil.java
Normal file
15
src/main/java/com/rosetta/im/protocol/util/StringUtil.java
Normal file
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
BIN
target/classes/com/rosetta/im/Main.class
Normal file
BIN
target/classes/com/rosetta/im/Main.class
Normal file
Binary file not shown.
BIN
target/classes/com/rosetta/im/device/Device.class
Normal file
BIN
target/classes/com/rosetta/im/device/Device.class
Normal file
Binary file not shown.
BIN
target/classes/com/rosetta/im/executors/Executor0Handshake.class
Normal file
BIN
target/classes/com/rosetta/im/executors/Executor0Handshake.class
Normal file
Binary file not shown.
BIN
target/classes/com/rosetta/im/packet/Packet0Handshake.class
Normal file
BIN
target/classes/com/rosetta/im/packet/Packet0Handshake.class
Normal file
Binary file not shown.
BIN
target/classes/com/rosetta/im/packet/enums/HandshakeStage.class
Normal file
BIN
target/classes/com/rosetta/im/packet/enums/HandshakeStage.class
Normal file
Binary file not shown.
BIN
target/classes/com/rosetta/im/protocol/Client.class
Normal file
BIN
target/classes/com/rosetta/im/protocol/Client.class
Normal file
Binary file not shown.
BIN
target/classes/com/rosetta/im/protocol/Server.class
Normal file
BIN
target/classes/com/rosetta/im/protocol/Server.class
Normal file
Binary file not shown.
BIN
target/classes/com/rosetta/im/protocol/Stream.class
Normal file
BIN
target/classes/com/rosetta/im/protocol/Stream.class
Normal file
Binary file not shown.
BIN
target/classes/com/rosetta/im/protocol/packet/Packet.class
Normal file
BIN
target/classes/com/rosetta/im/protocol/packet/Packet.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
target/classes/com/rosetta/im/protocol/util/StringUtil.class
Normal file
BIN
target/classes/com/rosetta/im/protocol/util/StringUtil.class
Normal file
Binary file not shown.
Reference in New Issue
Block a user